/*******************************************************************************
 * Copyright (c) 2013 by mHealth Corporation all right reserved.
 * KFuPay3DES.java
 * 2013-10-11 
 * 
 *******************************************************************************/
package com.zlq.cn.util.des.security;


import com.zlq.cn.util.des.hash.HrHex;

/**
 * <p>
 * business:
 * </p>
 * <p>
 * comment:
 * </p>
 * 
 * @version 2013-10-11
 * @author jimi yuan
 *         <p>
 *         History:
 *         </p>
 *         <p>
 *         1. Date:
 *         </p>
 *         <p>
 *         2. Author:
 *         </p>
 *         <p>
 *         3. Modification:
 *         </p>
 */
public class KFuPayTriDES {
	// private static final String ALGORITHM = "DESede/ECB/PKCS5Padding";

	/**
	 * 3DES加密，针对src长度不是8的整数倍的明文采用PKCS5Padding模式做填充
	 * 
	 * @param src
	 *            明文字符串
	 * @param key
	 *            加密密钥(双倍长密钥)
	 * @return 返回加密后的字节数组
	 * @throws Exception 
	 */
	public static byte[] encryptWithPKCS5Padding(String src, String key) throws Exception {
		byte[] byteKey = HrHex.decode(key);
		byte[] temp = src.getBytes();

		int length = temp.length;
		int blocks = length / 8 + 1; // 明文长度不管是否为8的整数倍都需要填充
		int padding = 8 - (byte) (length % 8);// 计算出填充字节
		byte[] byteSrc = new byte[blocks * 8];
		byte[] result = new byte[blocks * 8];

		int i = 0;
		for (i = 0; i < length; i++) {
			byteSrc[i] = temp[i];
		}

		for (int j = 0; j < blocks * 8 - length; j++) {// 对最后一个加密块做填充
			byteSrc[i++] = (byte) padding;
		}

		KFuPayDES des = new KFuPayDES("");
		for (int j = 0; j < blocks; j++) {// 每8个字节作为一个加密块，逐个循环加密
			byte[] srcTemp = new byte[8];
			for (int k = j * 8; k < (j + 1) * 8; k++) {// 拷贝一个块至临时字节数组，准备加密
				srcTemp[k % 8] = byteSrc[k];
			}

			byte[] encryTemp = des.triDesEncrypt(byteKey, srcTemp, KFuPayDES.DES_MODE_DES);
			for (int k = j * 8; k < (j + 1) * 8; k++) {// 加密一个块，并赋值至结果数组
				result[k] = encryTemp[k % 8];
			}
		}

		return result;
	}

	/**
	 * 3DES加密算法，针对src长度不是8的整数倍的明文采用PKCS5Padding模式做填充
	 * 
	 * @param src
	 *            明文字节数组
	 * @param key
	 *            加密密钥字节数组(双倍长密钥)
	 * @return 返回加密后的字节数组
	 */
	public static byte[] encryptWithPKCS5Padding(byte[] src, byte[] key) {
		int length = src.length;
		int blocks = length / 8 + 1;// 明文长度不管是否为8的整数倍都需要填充
		int padding = 8 - (length % 8);

		byte[] byteSrc = new byte[blocks * 8];
		byte[] result = new byte[blocks * 8];
		int i = 0;
		for (i = 0; i < length; i++) {
			byteSrc[i] = src[i];
		}

		for (int j = 0; j < blocks * 8 - length; j++) {
			byteSrc[i++] = (byte) padding;
		}

		KFuPayDES des = new KFuPayDES("");
		for (int j = 0; j < blocks; j++) {
			byte[] srcTemp = new byte[8];
			for (int k = j * 8; k < (j + 1) * 8; k++) {
				srcTemp[k % 8] = byteSrc[k];
			}

			byte[] encryTemp = des.triDesEncrypt(key, srcTemp, KFuPayDES.DES_MODE_DES);
			for (int k = j * 8; k < (j + 1) * 8; k++) {
				result[k] = encryTemp[k % 8];
			}
		}

		return result;
	}

	/**
	 * 3DES解密，自动删除PKCS5Padding模式下填充的数据
	 * 
	 * @param src
	 *            密文字节数组
	 * @param key
	 *            解密密钥字符串(双倍长密钥)
	 * @return 返回解密后的明文字节数组
	 * @throws Exception 
	 */
	public static byte[] decryptWithPKCS5Padding(byte[] src, String key) throws Exception {
		int length = src.length;
		if (0 != length % 8) {
			return null;
		}

		int blocks = length / 8;
		byte[] byteKey = HrHex.decode(key);
		byte[] resultTemp = new byte[blocks * 8];

		KFuPayDES des = new KFuPayDES("");
		for (int i = 0; i < blocks; i++) {
			// 拷贝一个密文块至临时数组，准备解密
			byte[] srcTemp = new byte[8];
			for (int j = i * 8; j < (i + 1) * 8; j++) {
				srcTemp[j % 8] = src[j];
			}

			// 解密一个块，并赋值至结果数组
			byte[] decrypTemp = des.triDesEncrypt(byteKey, srcTemp, KFuPayDES.DES_MODE_DES2);
			for (int j = i * 8; j < (i + 1) * 8; j++) {
				resultTemp[j] = decrypTemp[j % 8];
			}
		}

		int padding = resultTemp[resultTemp.length - 1];
		byte[] result = new byte[resultTemp.length - padding];
		System.arraycopy(resultTemp, 0, result, 0, result.length);

		return result;
	}

	/**
	 * 3DES解密，自动删除PKCS5Padding模式下填充的数据
	 * 
	 * @param src
	 *            密文字节数组
	 * @param key
	 *            解密密钥字节数组(双倍长密钥)
	 * @return 返回解密后的明文字节数组
	 */
	public static byte[] decryptWithPKCS5Padding(byte[] src, byte[] key) {
		int length = src.length;
		if (0 != length % 8) {
			return null;
		}

		int blocks = length / 8;
		byte[] resultTemp = new byte[blocks * 8];

		KFuPayDES des = new KFuPayDES("");
		for (int i = 0; i < blocks; i++) {
			// 拷贝一个密文块至临时数组，准备解密
			byte[] srcTemp = new byte[8];
			for (int j = i * 8; j < (i + 1) * 8; j++) {
				srcTemp[j % 8] = src[j];
			}

			// 解密一个块，并赋值至结果数组
			byte[] decryTemp = des.triDesEncrypt(key, srcTemp, KFuPayDES.DES_MODE_DES2);
			for (int j = i * 8; j < (i + 1) * 8; j++) {
				resultTemp[j] = decryTemp[j % 8];
			}
		}

		int padding = resultTemp[resultTemp.length - 1];
		byte[] result = new byte[resultTemp.length - padding];
		System.arraycopy(resultTemp, 0, result, 0, result.length);

		return result;
	}

	/**
	 * 3DES解密，不会删除填充数据(用于解密刷卡器加密的磁道信息)
	 * 
	 * @param src
	 *            密文字节数组
	 * @param key
	 *            解密密钥字符串(双倍长密钥)
	 * @return 返回解密后的明文字节数组
	 */
	public static byte[] decryptNOPKCS5Padding(byte[] src, String key) {
		int length = src.length;
		if (0 != length % 8) {
			return null;
		}

		int blocks = length / 8;
		byte[] byteKey = key.getBytes();
		byte[] result = new byte[blocks * 8];

		KFuPayDES des = new KFuPayDES("");
		for (int i = 0; i < blocks; i++) {
			// 拷贝一个密文块至临时数组，准备解密
			byte[] srcTemp = new byte[8];
			for (int j = i * 8; j < (i + 1) * 8; j++) {
				srcTemp[j % 8] = src[j];
			}

			// 解密一个块，并赋值至结果数组
			byte[] decrypTemp = des.triDesEncrypt(byteKey, srcTemp, KFuPayDES.DES_MODE_DES2);
			for (int j = i * 8; j < (i + 1) * 8; j++) {
				result[j] = decrypTemp[j % 8];
			}
		}

		return result;
	}

	/**
	 * 3DES解密，不会删除填充数据(用于解密刷卡器加密的磁道信息)
	 * 
	 * @param src
	 *            密文字节数组
	 * @param key
	 *            解密密钥字节数组(双倍长密钥)
	 * @return 返回解密后的明文字节数组
	 */
	public static byte[] decryptNOPKCS5Padding(byte[] src, byte[] key) {
		int length = src.length;
		if (0 != length % 8) {
			return null;
		}

		int blocks = length / 8;
		byte[] result = new byte[blocks * 8];

		KFuPayDES des = new KFuPayDES("");
		for (int i = 0; i < blocks; i++) {
			// 拷贝一个密文块至临时数组，准备解密
			byte[] srcTemp = new byte[8];
			for (int j = i * 8; j < (i + 1) * 8; j++) {
				srcTemp[j % 8] = src[j];
			}

			// 解密一个块，并赋值至结果数组
			byte[] decryTemp = des.triDesEncrypt(key, srcTemp, KFuPayDES.DES_MODE_DES2);
			for (int j = i * 8; j < (i + 1) * 8; j++) {
				result[j] = decryTemp[j % 8];
			}
		}

		return result;
	}

	// public static byte[] encrypt(byte[] src, String key) {
	// try {
	// DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
	// SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
	// SecretKey desKey = keyFactory.generateSecret(dks);
	//
	// Cipher cipher = Cipher.getInstance(ALGORITHM);
	// cipher.init(Cipher.ENCRYPT_MODE, desKey);
	// return cipher.doFinal(src);
	// } catch (Exception e) {
	// e.printStackTrace();
	// }
	//
	// return null;
	// }
	//
	// public static byte[] decrypt(byte[] src, String key) {
	// try {
	// DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
	// SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
	// SecretKey desKey = keyFactory.generateSecret(dks);
	//
	// Cipher cipher = Cipher.getInstance(ALGORITHM);
	// cipher.init(Cipher.DECRYPT_MODE, desKey);
	// return cipher.doFinal(src);
	// } catch (Exception e) {
	// e.printStackTrace();
	// }
	//
	// return null;
	// }
}
